// Copyright (c) 2012-2013, yuno. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
package sugarmintcandy.widgetwindow;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Build;
import android.view.Display;
import android.view.View;
import android.widget.AdapterViewAnimator;
import android.widget.TabHost;

public final class ApiHelper {
    @SuppressWarnings("deprecation")
    public static final int SDK_INT = Integer.parseInt(Build.VERSION.SDK);

    private ApiHelper() {
    }

    public static void setDisplayHomeAsUpEnabled(Activity a, boolean b) {
	impl.setDisplayHomeAsUpEnabled(a, b);
    }

    public static boolean isAdvanceable(Object view) {
	return impl.isAdvanceable(view);
    }

    public static void fyiWillBeAdvancedByHostKThx(Object view) {
	impl.fyiWillBeAdvancedByHostKThx(view);
    }

    public static void advance(Object view) {
	impl.advance(view);
    }

    public static int getAutoAdvanceViewId(AppWidgetProviderInfo info) {
	return impl.getAutoAdvanceViewId(info);
    }

    public static Rect getDefaultPaddingForWidget(Context context,
	    ComponentName component, Rect padding) {
	return impl.getDefaultPaddingForWidget(context, component, padding);
    }

    public static void startForeground(Service service, int id,
	    Notification notification) {
	impl.startForeground(service, id, notification);
    }

    public static void stopForeground(Service service, int id,
	    boolean removeNotification) {
	impl.stopForeground(service, id, removeNotification);
    }

    public static void startIntentSender(Activity activity,
	    PendingIntent intent, Intent fillInIntent, int flagsMask,
	    int flagsValues, int extraFlags)
	    throws PendingIntent.CanceledException {
	impl.startIntentSender(activity, intent, fillInIntent, flagsMask,
		flagsValues, extraFlags);
    }

    public static void setIndicator(TabHost.TabSpec spec, View view) {
	impl.setIndicator(spec, view);
    }

    public static int getRawHeight(Display display) {
	return impl.getRawHeight(display);
    }

    public static int getLauncherLargeIconSize(Context context) {
	return impl.getLauncherLargeIconSize(context);
    }

    private static final Cupcake impl;
    static {
	if (SDK_INT >= 15) {
	    impl = new IceCreamSandwichMR1();
	} else if (SDK_INT >= 14) {
	    impl = new IceCreamSandwich();
	} else if (SDK_INT >= 13) {
	    impl = new HoneycombMR2();
	} else if (SDK_INT >= 11) {
	    impl = new Honeycomb();
	} else if (SDK_INT >= 5) {
	    impl = new Eclair();
	} else if (SDK_INT >= 4) {
	    impl = new Donut();
	} else {
	    impl = new Cupcake();
	}
    }

    private static class Cupcake {
	public void setDisplayHomeAsUpEnabled(Activity a, boolean b) {
	}

	public boolean isAdvanceable(Object view) {
	    return false;
	}

	public void fyiWillBeAdvancedByHostKThx(Object view) {
	}

	public void advance(Object view) {
	}

	public int getAutoAdvanceViewId(AppWidgetProviderInfo info) {
	    return View.NO_ID;
	}

	public Rect getDefaultPaddingForWidget(Context context,
		ComponentName component, Rect padding) {
	    if (padding == null) {
		padding = new Rect();
	    } else {
		padding.set(0, 0, 0, 0);
	    }
	    return padding;
	}

	public void startForeground(Service service, int id,
		Notification notification) {
	    try {
		Service.class.getMethod("setForeground", boolean.class).invoke(
			service, true);
	    } catch (Throwable ex) {
		Debug.warn(ex);
	    }
	    NotificationManager nm = (NotificationManager) service
		    .getSystemService(Context.NOTIFICATION_SERVICE);
	    nm.notify(id, notification);
	}

	public void stopForeground(Service service, int id,
		boolean removeNotification) {
	    if (removeNotification) {
		NotificationManager nm = (NotificationManager) service
			.getSystemService(Context.NOTIFICATION_SERVICE);
		nm.cancel(id);
	    }
	}

	public void startIntentSender(Activity activity, PendingIntent intent,
		Intent fillInIntent, int flagsMask, int flagsValues,
		int extraFlags) throws PendingIntent.CanceledException {
	    throw new UnsupportedOperationException();
	}

	public void setIndicator(TabHost.TabSpec spec, View view) {
	    throw new UnsupportedOperationException();
	}

	@SuppressWarnings("deprecation")
	public int getRawHeight(Display display) {
	    return display.getHeight();
	}

	public int getLauncherLargeIconSize(Context context) {
	    return context.getResources().getDimensionPixelSize(
		    android.R.dimen.app_icon_size);
	}
    }

    @TargetApi(4)
    private static class Donut extends Cupcake {
	@Override
	public void setIndicator(TabHost.TabSpec spec, View view) {
	    spec.setIndicator(view);
	}
    }

    @TargetApi(5)
    private static class Eclair extends Donut {
	@Override
	public void startForeground(Service service, int id,
		Notification notification) {
	    service.startForeground(id, notification);
	}

	@Override
	public void stopForeground(Service service, int id,
		boolean removeNotification) {
	    service.stopForeground(removeNotification);
	}

	@Override
	public void startIntentSender(Activity activity, PendingIntent intent,
		Intent fillInIntent, int flagsMask, int flagsValues,
		int extraFlags) throws PendingIntent.CanceledException {
	    try {
		activity.startIntentSender(intent.getIntentSender(),
			fillInIntent, flagsMask, flagsValues, extraFlags);
	    } catch (SendIntentException ex) {
		throw new PendingIntent.CanceledException(ex);
	    }
	}
    }

    @TargetApi(11)
    private static class Honeycomb extends Eclair {
	@Override
	public void setDisplayHomeAsUpEnabled(Activity a, boolean b) {
	    a.getActionBar().setDisplayHomeAsUpEnabled(b);
	}

	@Override
	public boolean isAdvanceable(Object view) {
	    return view instanceof AdapterViewAnimator;
	}

	@Override
	public void fyiWillBeAdvancedByHostKThx(Object view) {
	    ((AdapterViewAnimator) view).fyiWillBeAdvancedByHostKThx();
	}

	@Override
	public void advance(Object view) {
	    ((AdapterViewAnimator) view).advance();
	}

	@Override
	public int getAutoAdvanceViewId(AppWidgetProviderInfo info) {
	    return info.autoAdvanceViewId;
	}

	@Override
	public int getLauncherLargeIconSize(Context context) {
	    ActivityManager am = (ActivityManager) context
		    .getSystemService(Context.ACTIVITY_SERVICE);
	    return am.getLauncherLargeIconSize();
	}
    }

    @TargetApi(13)
    private static class HoneycombMR2 extends Honeycomb {
	private static Method getRawHeight;

	static {
	    try {
		getRawHeight = Display.class.getMethod("getRawHeight");
	    } catch (NoSuchMethodException ex) {
		Debug.warn(ex);
	    }
	}

	@Override
	public int getRawHeight(Display display) {
	    if (getRawHeight != null) {
		try {
		    return (Integer) getRawHeight.invoke(display);
		} catch (ClassCastException ex) {
		    Debug.warn(ex);
		    getRawHeight = null;
		} catch (IllegalAccessException ex) {
		    Debug.warn(ex);
		    getRawHeight = null;
		} catch (InvocationTargetException ex) {
		    Debug.warn(ex);
		}
	    }
	    return super.getRawHeight(display);
	}
    }

    @TargetApi(14)
    private static class IceCreamSandwich extends HoneycombMR2 {
	@Override
	public Rect getDefaultPaddingForWidget(Context context,
		ComponentName component, Rect padding) {
	    if (padding == null) {
		padding = new Rect();
	    }
	    try {
		PackageManager packageManager = context.getPackageManager();
		ApplicationInfo appInfo = packageManager.getApplicationInfo(
			component.getPackageName(), 0);
		if (appInfo.targetSdkVersion >= 14) {
		    int size = context.getResources().getDimensionPixelSize(
			    R.dimen.default_app_widget_padding_ics);
		    padding.left = size;
		    padding.right = size;
		    padding.top = size;
		    padding.bottom = size;
		}
	    } catch (PackageManager.NameNotFoundException ex) {
		// ignore
	    }
	    return padding;
	}
    }

    @TargetApi(15)
    private static class IceCreamSandwichMR1 extends IceCreamSandwich {
	@Override
	public Rect getDefaultPaddingForWidget(Context context,
		ComponentName component, Rect padding) {
	    return AppWidgetHostView.getDefaultPaddingForWidget(context,
		    component, padding);
	}
    }
}
